#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include "driver/timer.h"
#include "stepperIndex.h"



// DIY模块地址: https://shop64022682.taobao.com/
// 引脚定义
#define DIR_PIN 26
#define STEP_PIN 27
#define LIMIT_LEFT_PIN 35    // 对应插槽 LIMIT_2
#define LIMIT_RIGHT_PIN 34   // 对应插槽 LIMIT_1
#define MS_JUMPER 1  //MS引脚跳线值(分频系数的倒数)

#define USE_WIFI_MODE_AP // 屏蔽此行，WIFI设置为客户端模式（需要连接路由器），打开此行，WIFI设置为AP模式(ESP32就是一个WIFI热点，不用连接路由器)

#ifdef USE_WIFI_MODE_AP
const char *ssid = "wifiStepperControl"; // AP模式的WIFI热点名称
const char *password = "12345678";// WIFI密码
#else
const char *ssid = "myTest"; // 客户端模式下所要连接的WIFI热点名称，如家里使用的无线路由器WIFI热点名称
const char *password = "12345678"; // 客户端模式下所要连接的WIFI密码，如家里使用的无线路由器WIFI密码
#endif

// 运动参数
const float stepsPerRev = (360.0 / 18)*MS_JUMPER;  // 每转步数 (360度/1.8度步距角)
const float lead = 3.0;                 // 丝杠导程(mm)
const float stepsPerMM = stepsPerRev / lead; // 每毫米步数
const int maxPosition = 60;             // 最大行程(mm)
float currentPosition = 0;     // 当前位置(mm)
int moveMode = 0;              // 0=停止,1=手动,2=往复,3=右进,4=左进,5=左限位,6=右限位
bool autoReverse = false;      // 往复运动方向
int stepFrequency = 300;       // 步进频率(Hz)
int pulseWidth = 500;          // 脉冲宽度(us)

// 定时器控制变量
int stepCnt = 0;               // 步进脉冲计数器
int targetSteps = 0;           // 目标步数
int currentDirection = LOW;    // 当前方向
bool isMoving = false;         // 是否正在移动

// Web服务器
WebServer server(80);

// 定时器中断回调函数
void IRAM_ATTR timer_group0_isr(void *para) {
  // 清除中断标志
  timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
  // 重新使能报警
  timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0);

  // 只有在移动状态下才生成脉冲
  if (isMoving) {
    // 翻转步进引脚电平
    digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));
    
    // 在上升沿计数
    if (digitalRead(STEP_PIN)) {
      // 更新位置
      currentPosition += (currentDirection == LOW) ? 1.0/stepsPerMM : -1.0/stepsPerMM;
      stepCnt++;      
      // 往复运动模式边界需要特殊处理
      if(moveMode == 2) {
        // 检查限位开关
        if (currentDirection == LOW && digitalRead(LIMIT_RIGHT_PIN) == LOW) {
          // currentPosition = maxPosition;
          stepCnt = 0;
          // Serial.println("RIGHT===");
          currentDirection = (currentDirection == LOW) ? HIGH : LOW;
          digitalWrite(DIR_PIN, currentDirection);
        } 
        else if (currentDirection == HIGH && digitalRead(LIMIT_LEFT_PIN) == LOW) {
          currentPosition = 0;
          stepCnt = 0;
          // Serial.println("LEFT===");
          currentDirection = (currentDirection == LOW) ? HIGH : LOW;
          digitalWrite(DIR_PIN, currentDirection);
        }
        // 检查是否达到目标步数
        if (stepCnt >= targetSteps) {
          // ("MAX===");
          stepCnt = 0;
          targetSteps = maxPosition* stepsPerMM;
          currentDirection = (currentDirection == LOW) ? HIGH : LOW;
          digitalWrite(DIR_PIN, currentDirection);
        }
      }else {
        // 检查限位开关
        if (currentDirection == LOW && digitalRead(LIMIT_RIGHT_PIN) == LOW) {
          // currentPosition = maxPosition;
          moveMode = 0;
          isMoving = false;
          timer_pause(TIMER_GROUP_0, TIMER_0);
        } 
        else if (currentDirection == HIGH && digitalRead(LIMIT_LEFT_PIN) == LOW) {
          currentPosition = 0;
          moveMode = 0;
          isMoving = false;
          timer_pause(TIMER_GROUP_0, TIMER_0);
        }
        // 检查是否达到目标步数
        if (targetSteps > 0 && stepCnt >= targetSteps) {
          moveMode = 0;
          isMoving = false;
          stepCnt = 0;
          targetSteps = 0;
          timer_pause(TIMER_GROUP_0, TIMER_0);
        }
      }
    }
  }
}

// 定时器初始化
void Time_Init() {
  timer_config_t config;
  config.divider = 8; // 分频系数
  config.counter_dir = TIMER_COUNT_UP; // 向上计数
  config.counter_en = TIMER_PAUSE; // 初始暂停
  config.alarm_en = TIMER_ALARM_EN; // 启用报警
  config.auto_reload = TIMER_AUTORELOAD_EN; // 自动重载 (修改为常量)
  config.intr_type = TIMER_INTR_LEVEL; // 中断类型
  
  timer_init(TIMER_GROUP_0, TIMER_0, &config);
  timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0x00000000ULL);
  
  // 计算定时器报警值 (单位: 计数器ticks)
  // 定时器时钟频率 = 80MHz / 8 = 10MHz
  // 报警值 = 10,000,000 / (2 * 步进频率)
  uint64_t alarm_value = 10000000 / (2 * stepFrequency);
  if (alarm_value < 1) alarm_value = 1; // 确保最小值
  
  timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, alarm_value);
  
  timer_enable_intr(TIMER_GROUP_0, TIMER_0);
  timer_isr_register(TIMER_GROUP_0, TIMER_0, timer_group0_isr, NULL, ESP_INTR_FLAG_IRAM, NULL);
}

// 设置步进频率
void SetStepFreq(unsigned int freq) {
  if (freq == 0) {
    timer_pause(TIMER_GROUP_0, TIMER_0);
    return;
  }
  
  // 计算定时器报警值 (单位: 计数器ticks)
  // 定时器时钟频率 = 80MHz / 8 = 10MHz
  // 报警值 = 10,000,000 / (2 * 步进频率)
  uint64_t alarm_value = 10000000 / (2 * freq);
  if (alarm_value < 1) alarm_value = 1; // 确保最小值
  
  timer_pause(TIMER_GROUP_0, TIMER_0);
  timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, alarm_value);
  timer_start(TIMER_GROUP_0, TIMER_0);
}

// 步进电机初始化
void setupStepper() {
  pinMode(DIR_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
  pinMode(LIMIT_LEFT_PIN, INPUT_PULLUP);
  pinMode(LIMIT_RIGHT_PIN, INPUT_PULLUP);
  
  // 初始化定时器
  Time_Init();
  SetStepFreq(0); // 初始停止状态
}

// 启动步进电机移动
void startMove(int steps, int direction) {
  if (steps <= 0) return;
  
  digitalWrite(DIR_PIN, direction);
  currentDirection = direction;
  targetSteps = steps;
  stepCnt = 0;
  isMoving = true;
  
  // 设置频率并启动定时器
  SetStepFreq(stepFrequency);
}

// 处理控制命令
void handleControl() {
  String message = "OK";
  
  // 位置控制
  if (server.hasArg("position")) {
    int target = server.arg("position").toInt();
    target = constrain(target, 0, maxPosition);
    int steps = abs(target - currentPosition) * stepsPerMM;
    int dir = (target > currentPosition) ? LOW : HIGH ;
    
    // 停止当前运动
    SetStepFreq(0);
    isMoving = false;
    
    // 启动新运动
    startMove(steps, dir);
    moveMode = 1; // 手动模式
  }
  // 往复运动
  else if (server.hasArg("auto")) {
    // Serial.println("======CMD auto======");
    moveMode = 2;
    autoReverse = !autoReverse;
    startMove(maxPosition* stepsPerMM, autoReverse ? HIGH : LOW); // 0表示连续运动
  }
  // 右进10mm
  else if (server.hasArg("fwd10")) {
    startMove(10 * stepsPerMM, LOW);
    moveMode = 3;
  }
  // 左进10mm
  else if (server.hasArg("back10")) {
    startMove(10 * stepsPerMM, HIGH);
    moveMode = 4;
  }
  // 停止
  else if (server.hasArg("stop")) {
    // Serial.println("======CMD stop======");
    moveMode = 0;
    isMoving = false;
    targetSteps = 0;
    SetStepFreq(0);
  }
  // 检测左限位
  else if (server.hasArg("findLeft")) {
    startMove(10000, HIGH); // 设置一个大数确保到达限位
    moveMode = 5;
  }
  // 检测右限位
  else if (server.hasArg("findRight")) {
    startMove(10000, LOW); // 设置一个大数确保到达限位
    moveMode = 6;
  }
  // 频率控制
  else if (server.hasArg("freq")) {
    stepFrequency = server.arg("freq").toInt();
    stepFrequency = constrain(stepFrequency, 0, 1000);
    pulseWidth = (stepFrequency > 0) ? 500000 / stepFrequency : 0;
    
    // 如果正在移动，更新频率
    if (isMoving) {
      SetStepFreq(stepFrequency);
    }
  }
  
  server.send(200, "text/plain", message);
}

// 处理状态请求
void handleStatus() {
  String json = "{\"position\":" + String(currentPosition) + 
               ",\"frequency\":" + String(stepFrequency) + "}";
  server.send(200, "application/json", json);
}

// 处理根路径
void handleRoot() {
  server.send(200, "text/html; charset=utf-8", html_page);
}

void setup() {
  Serial.begin(115200);
  
  // 初始化步进电机
  setupStepper();
#ifdef USE_WIFI_MODE_AP
  // 初始化AP模式下WIFI参数
  // 设置小车的IP地址为192.168.0.1，对应浏览器中输入的小车网址192.168.0.1
  // WiFi.softAPConfig(IPAddress("192.168.0.1"), IPAddress("192.168.0.1"), IPAddress("255.255.255.0"));
  WiFi.softAPConfig(IPAddress(192, 168, 0, 1), IPAddress(192, 168, 0, 1), IPAddress(255,255,255,0));
  // 设置WIFI热点名称,密码
  WiFi.softAP(ssid, password);
  // 通过串口打印WIFI参数
  Serial.println("WIFI SSID:");
  Serial.println(ssid);
  Serial.println("WIFI Password:");
  Serial.println(password);  
  Serial.print("Camera Ready! Use 'http://");
  Serial.print(WiFi.softAPIP());
  Serial.println("' to connect");
#else  
  // 连接WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP()); 
#endif 
  // 设置Web服务器路由
  server.on("/", handleRoot);
  server.on("/control", handleControl);
  server.on("/status", handleStatus);
  server.begin();
}

void loop() {
  // 处理客户端请求
  server.handleClient();
  
  // 短暂延迟防止WDT复位
  delay(10);
}